package com.example.demo.management.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.constant.EnumConstant;
import com.example.demo.constant.ResponseMsg;
import com.example.demo.mapper.SmateMapper;
import com.example.demo.util.ClassFactoryUtils;
import com.example.demo.util.JgitUtils;
import com.example.demo.vo.Smate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * 元表管理
 *
 * @author zhangfc
 * @date 2021/12/28 16:19
 */
@Service
@Slf4j
public class BaseCurService {

    @Value("${package}")
    private String pacakge;

    @Resource
    private SmateMapper smateMapper;


    /**
     * 新增或更新实体类代码 service
     *
     * @param jsonString json串
     * @return ResponseMsg
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseMsg saveOrUpdateBtable(String jsonString) {

        //定义要生成实体文件的字符
        StringBuffer fileWriter = new StringBuffer("");

        //定义要生成mapper文件的字符
        StringBuffer mapperFilterWriter = new StringBuffer("");

        //json -> Map
        Map<String, Object> paramMap = JSONUtil.toBean(jsonString, Map.class);
        final String tableName = Convert.toStr(paramMap.get("tableName"));
        final String name = Convert.toStr(paramMap.get("name"));
        final String remark = Convert.toStr(paramMap.get("remark"));

        //检查要保存的表名字是否存在
        Set<Class<?>> classes = ClassFactoryUtils.getClasses(pacakge);
        List<String> voNameList = classes.stream()
                .map(mclass -> CollUtil.getLast(StrUtil.split(mclass.getName(), '.')))
                .collect(Collectors.toList());

        Smate smate = Smate.builder()
                .itable(tableName)
                .name(name)
                .remark(remark)
                .build();
        if (CollUtil.contains(voNameList, tableName)) {
            //如果表存在执行更新操作
            QueryWrapper<Smate> updateWrepper = new QueryWrapper<>();
            updateWrepper.eq("table", tableName);
            smateMapper.update(smate, updateWrepper);
        } else {
            //否则保存
            smateMapper.insert(smate);
        }

        //生成实体文件
        //加上导包的字符
        fileWriter = paddingPackage(fileWriter, tableName);

        fileWriter.append("public class " + tableName + " {\n\n\n")
                .append("\t@Id\n")
                .append("\t@TableId\n")
                .append("\t@GeneratedValue(strategy = GenerationType.IDENTITY)\n")
                .append("\tprivate Integer " + StrUtil.lowerFirst(tableName) + "Id;\n\n\n");
        List<Map> list = JSONUtil.toList(Convert.toStr(paramMap.get("colums")), Map.class);
        for (Map map : list) {
            //获取要生成的字段和类型
            String key = Convert.toStr(map.get("key"));
            String type = Convert.toStr(map.get("type"));
            fileWriter.append("\tprivate " + type + " " + key + ";\n\n\n");
        }
        fileWriter.append("}");

        //生成mapper文件
        mapperFilterWriter = paddingMapperPackage(mapperFilterWriter, tableName);

        try {
            //生成实体类
            String path = System.getProperty("user.dir");
            File file = new File(path + EnumConstant.filePath.VO_PATH + File.separatorChar, tableName + ".java");
            //如果文件不存在或者文件不是目录则创建
            if (!file.exists()) {
                //先创建文件再写入
                file.createNewFile();
                OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
                BufferedWriter bw = new BufferedWriter(fw);
                bw.write(fileWriter.toString());
                bw.close();
            } else {
                //否则更新文件  D:\idea_project\spring_dev\src\main\java\com\example\demo\vo
                OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
                BufferedWriter bw = new BufferedWriter(fw);
                bw.write(fileWriter.toString());
                bw.close();
            }
            //生成mapper文件
            File mapperFile = new File(path + EnumConstant.filePath.MAPPER_PATH + File.separatorChar, StrUtil.upperFirst(tableName) + "Mapper.java");
            //不存在则创建 存在则更新
            if (!mapperFile.exists()) {
                mapperFile.createNewFile();
                OutputStreamWriter mfw = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
                BufferedWriter mbw = new BufferedWriter(mfw);
                mbw.write(mapperFilterWriter.toString());
                mbw.close();
            } else {
                OutputStreamWriter mfw = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
                BufferedWriter mbw = new BufferedWriter(mfw);
                mbw.write(mapperFilterWriter.toString());
                mbw.close();
            }
            //add文件并提交
            JgitUtils.gitAdd();

            JgitUtils.gitPull();

            JgitUtils.gitCommit("update");

            JgitUtils.gitPush();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseMsg.error();
        }

        return ResponseMsg.ok();
    }

    private static Lock reentrantLock = new ReentrantLock();

    /**
     * 测试更新表
     *
     * @param jsonString 测试串
     */
    public int updateBtable(String jsonString) {
        int insert = 0;
        //修改数据方法和查询的方法共用一个锁
        reentrantLock.lock();
        try {
            Smate smate = Smate.builder()
                    .name("测试1")
                    .remark("我是个测试")
                    .itable("玩哇").build();

            insert = smateMapper.insert(smate);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //修改数据方法和查询的方法共用一个锁
            reentrantLock.unlock();
        }
        return insert;
    }

    /**
     * 获取所有的元表数据
     *
     * @return
     */
    public List<Map<String, Object>> getAllTable() {
        List<Smate> smates = new ArrayList<>();
        //修改数据方法和查询的方法共用一个锁
        try {
            reentrantLock.lock();
            smates = smateMapper.listAllSmate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
        return smates.stream()
                .map((smate) -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("table", smate.getItable());
                    map.put("tableName", smate.getName());
                    map.put("remark", smate.getRemark());
                    return map;
                }).collect(Collectors.toList());
    }

    /**
     * 加上导包的字符
     *
     * @param fileWriter 输出的字符
     * @param tableName  文件名
     */
    private StringBuffer paddingPackage(StringBuffer fileWriter, String tableName) {
        fileWriter.append("package ")
                .append(pacakge + ";\n\n")
                .append("import com.baomidou.mybatisplus.annotation.TableId;\n")
                .append("import lombok.AllArgsConstructor;\n")
                .append("import lombok.Builder;\n")
                .append("import lombok.Data;\n")
                .append("import lombok.NoArgsConstructor;\n")
                .append("import org.springframework.format.annotation.DateTimeFormat;\n")
                .append("import javax.persistence.*;\n")
                .append("import java.util.*;\n\n\n")
                .append("/**\n")
                .append(" *@author zhangfc\n")
                .append(" *@date " + new Date() + "\n")
                .append(" */\n")
                .append("@Entity\n")
                .append("@Data\n")
                .append("@AllArgsConstructor\n")
                .append("@NoArgsConstructor\n")
                .append("@Table(name = \"" + tableName + "\")\n")
                .append("@Builder(toBuilder = true)\n");
        return fileWriter;
    }

    /**
     * mapper 文件导包的处理
     *
     * @param mapperFilterWriter mapper文件的字符处理
     * @param tableName          表名
     * @return StringBuffer
     */
    private StringBuffer paddingMapperPackage(StringBuffer mapperFilterWriter, String tableName) {

        mapperFilterWriter.append("package com.example.demo.mapper;\n\n")
                .append("import com.baomidou.mybatisplus.core.mapper.BaseMapper;\n")
                .append("import com.example.demo.vo.*;\n")
                .append("import org.apache.ibatis.annotations.*;\n\n\n\n")
                .append("/**\n")
                .append(" * @author zhangfc\n")
                .append(" * @date ")
                .append(LocalDateTimeUtil.format(LocalDateTimeUtil.now(), "yyyy-MM-dd HH:mm:ss"))
                .append("\n")
                .append(" */\n")
                .append("@Mapper\n")
                .append("public interface ")
                .append(StrUtil.upperFirst(tableName))
                .append("Mapper extends BaseMapper<" + StrUtil.upperFirst(tableName) + "> {\n\n\n\n\n")
                .append("}");
        return mapperFilterWriter;
    }


}
